<template>
  <div class="nav">
    <div class="nav-second">
      <div class="input-box">
        <el-input v-model="input3" placeholder="请输入对应关键信息" clearable class="input-with-select">
          <template #prepend>
            <el-select @change="selectSpace" v-model="select" placeholder="选项项目" style="width: 115px">
              <el-option v-for="(item, index) in spaceList" :key="item.id" :label="item.space_name"
                :value="item.space_id" />
            </el-select>
          </template>
          <template #append>
            <el-button :icon="Search" @click="serach" />
          </template>
        </el-input>
      </div>
      <div>
        <el-popover placement="left-end" effect="dark" width="auto" trigger="click">
          <template #reference>
            <el-button type="primary" round>上传队列</el-button>
          </template>
          <div class="uploadQueue">
            <h3>上传队列</h3>
            <div v-for="item in uploadQueue" :key="item.id">
              <div>{{ item.name }}</div>
              <div class="upload-item">
                <div style="width: 90%">
                  <el-progress :percentage="100" :status="item.status === 'uploading'
                    ? ''
                    : item.status === 'success'
                      ? 'success'
                      : 'exception'
                    " :indeterminate="true" />
                </div>
                <span :class="`status-${item.status}`">{{
                  item.status === "uploading"
                    ? "上传中"
                    : item.status === "success"
                      ? "成功"
                      : "失败"
                }}</span>
                <el-button @click="removeFileFromQueue(item.id)">删除</el-button>
              </div>
            </div>
          </div>
        </el-popover>
        <el-popover placement="left-end" effect="dark" width="auto" trigger="click" @show="showLog">
          <template #reference>
            <el-button type="primary" round>实时日志</el-button>
          </template>
          <div>websocket服务在线连接客户端:{{ connectNumber }}个</div>
          <div ref="logContainer" class="logComponent">
            <div class="row" v-for="(item, index) in logList" :key="index">
              <div>
                {{ item }}
              </div>
              <el-divider />
            </div>
          </div>
        </el-popover>
      </div>
    </div>
    <div id="fileDragArea" :style="{
      height: dragUplodFlag ? '100px' : '0px',
      border: dragUplodFlag ? '1px solid #ccc' : 'none',
      transform: dragUplodFlag ? 'scale(1)' : 'scale(0)',
      margin: dragUplodFlag ? '10px 0px' : '0px 0px',
    }" @drop="handleMultipleFileDrop" @dragover.prevent @dragenter.prevent>
      请将文件拖入此区域上传
    </div>
    <div class="test">
      <div class="block" :style="{
        left: index * 150 + 'px',
        '--index': index * 0.1 + 's',
        '--index2': 2 + index * 0.2 + 's',
        '--x': (index + 1) * 10 + 'px',
      }" v-for="(item, index) in animals" :key="index">
        <el-button style="width: 100%" type="primary" size="large" @click="getEvent(item.id)"
          v-if="select || (!select && index == 0)">
          <el-icon v-if="index == 0">
            <CirclePlus />
          </el-icon>
          <el-icon v-else-if="index == 1">
            <Pointer />
          </el-icon>
          <el-icon v-else>
            <Upload />
          </el-icon>
          {{ item.value }}</el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import {
  ref,
  reactive,
  onUnmounted,
  onMounted,
  getCurrentInstance,
  watch,
  nextTick,
} from "vue";
import { ArrowLeft } from "@element-plus/icons-vue";
import { Search, CirclePlus, Pointer, Upload } from "@element-plus/icons-vue";
import {
  getAllFileSpace,
  addfilespace,
  addfile,
  addBigFile
} from "@/api/serveFile/index.ts";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance();
const input3 = ref("");
const select = ref("");
const dragUplodFlag = ref(false);
const emit = defineEmits(["change"]);
//查看实时日志
const logFlag = ref(false);
const lookLog = () => {
  console.log("----");
  logFlag.value = !logFlag.value;
};
const logList = ref([]);
const logContainer = ref(null);
const connectNumber = ref(0);
//打开日志的时候默认滚动到最新的日志
const showLog = () => {
  scrollToBottom();
};
// 滚动到底部的函数
const scrollToBottom = () => {
  nextTick(() => {
    if (logContainer.value) {
      logContainer.value.scrollTop = logContainer.value.scrollHeight;
    }
  });
};
//监听变化自动滚动到最新日志
watch(logList, () => {
  scrollToBottom();
});
//websocket服务通信逻辑
let socket;
let isConnecting = false; // 用于防止重复连接
let reconnectInterval = 1000; // 初始重连间隔时间（毫秒）
const maxReconnectInterval = 30000; // 最大重连间隔时间（毫秒）
const reconnectJitter = 1000; // 随机抖动时间，以减少多个客户端同时重连
let timer = null;
let shouldReconnect = true; // 控制是否应该重连

function connectWebSocket() {
  if (isConnecting || !shouldReconnect) return;
  isConnecting = true;
  socket = new WebSocket("ws://localhost:8088");

  socket.onopen = function () {
    console.log("已连接到WebSocket服务器，开始接收日志信息");
    isConnecting = false;
    reconnectInterval = 1000; // 重置重连间隔时间
  };

  socket.onmessage = function (event) {
    const { message_type, data } = JSON.parse(event.data);
    if (message_type == "send_content") {
      if (data.type == 1 && data.content) {
        logList.value = [];
        logList.value = data.content.split(/\r|\n/).filter((item) => item);
      }
      if (data.type == 2 && data.content) {
        logList.value = logList.value.concat(
          data.content.split(/\r|\n/).filter((item) => item)
        );
      }
    }
    if (message_type == "clients_total_number") {
      connectNumber.value = data.connect_number;
    }
    if (message_type == "server_error") {
      console.log(data.error_info);
    }
  };

  socket.onerror = function (error) {
    console.error("WebSocket连接出错:", error);
    startReconnect();
  };

  socket.onclose = function (event) {
    console.log(
      "与WebSocket服务器的连接已关闭",
      event.code,
      event.reason,
      socket
    );
    startReconnect();
  };
}

function startReconnect() {
  if (!shouldReconnect) return;
  if (socket) {
    reconnectInterval = Math.min(reconnectInterval * 2, maxReconnectInterval);
    const jitter = Math.random() * reconnectJitter;
    setTimeout(connectWebSocket, reconnectInterval + jitter);
  }
}

// 初始化WebSocket连接
onMounted(() => {
  shouldReconnect = true;
  connectWebSocket();
});

// 页面卸载时处理
onUnmounted(() => {
  shouldReconnect = false;
  if (socket) {
    socket.close();
    socket = undefined;
  }
});
const animals = ref([
  {
    value: "新建项目空间",
    id: 1,
  },
  {
    value: "拖拽上传",
    id: 2,
  },
  {
    value: "上传文件",
    id: 3,
  },
  {
    value: "上传文件夹",
    id: 4,
  },
  {
    value: "分片上传",
    id: 5,
  },
]);
const uploadQueue = ref([]); // 上传队列
const uploadProgress = ref({}); // 每个文件的上传进度
const spaceList = ref([]);
onMounted(() => {
  getFileSpaceList();
});
const getFileSpaceList = async () => {
  spaceList.value = [];
  try {
    spaceList.value.push({
      space_name: "全部空间",
      space_id: "",
    });
    spaceList.value = spaceList.value.concat(await getAllFileSpace());
    emit("change", {
      spaceId: select.value,
      inputValue: input3.value,
    });
  } catch (error) {
    console.log(error);
  }
};
//搜索相关文件
const serach = () => {
  console.log(input3.value);
  emit("change", {
    spaceId: select.value,
    inputValue: input3.value,
  });
};
//空间切换
const selectSpace = () => {
  input3.value = "";
  dragUplodFlag.value = false;
  emit("change", {
    spaceId: select.value,
    inputValue: input3.value,
  });
};
//切换事件
const getEvent = (val) => {
  switch (val) {
    case 1:
      return handleCreatItemDir();
      break;
    case 2:
      return (dragUplodFlag.value = !dragUplodFlag.value);
      break;
    case 3:
      return handleFileUpload();
      break;
    case 4:
      return handleUploadDir();
      break;
    case 5:
      return handleUploadChunck();
      break;
    default:
      return "";
      break;
  }
};
//分片上传
const handleUploadChunck = () => {
  console.log("分片上传");
  let input = document.createElement("input");
  input.type = "file";
  // 可以设置多个文件上传
  // input.multiple = true;
  // 可以设置文件类型过滤
  // input.accept = ".jpg,.png,.webp";
  input.addEventListener("change", async (event) => {
    // 获取选中的文件列表
    var files = event.target.files;
    for (var i = 0; i < files.length; i++) {
      var file = files[i];
      try {

        const spaceId = select.value; // 替换为实际的空间 ID
        const chunkSize = 300 * 1024; // 每个分片的大小，这里设置为 1MB
        const totalChunks = Math.ceil(file.size / chunkSize);

        // 计算文件哈希（这里简单使用文件名作为示例，实际应用中建议使用更安全的哈希算法）
        const fileHash = proxy.$nextId();
        let uploadId = ''
        // 分割文件并上传分片
        for (let i = 0; i < totalChunks; i++) {
          const start = i * chunkSize;
          const end = Math.min(start + chunkSize, file.size);
          const chunk = file.slice(start, end);

          const formData = new FormData();
          formData.append('file', chunk);
          if (i != 0) {//除第一个分片外，都需要传递第一个分片接口返回的uploadId标识
            formData.append('uploadId', uploadId);
          }
          formData.append('fileHash', fileHash);
          formData.append('fileType', Number(proxy.$gf.gft(file.name).value));
          formData.append('remark', '分片上传');
          //上传当前分片大小
          formData.append('currentSize', chunk.size);
          formData.append('totalSize', file.size);//总文件大小
          formData.append('fileName', file.name);//文件名
          formData.append('chunkIndex', i);
          formData.append('totalChunks', totalChunks);

          try {
            const result = await addBigFile(formData, {
              spaceId
            }, (val) => {
              //文件的上传进度
              console.log(`文件---[${file.name}]---上传进度${val}`);
            });
            console.log(`分片 ${i + 1} 上传结果:`, result);
            if (i == 0) {
              console.log(result, "---------");
              uploadId = result.uploadId;
            }
          } catch (error) {
            console.error(`分片 ${i + 1} 上传出错:`, error);
          }
        }
        ElMessage({
          type: "success",
          message: `所有分片上传完成`,
        });
      } catch (error) {
        console.log(error);
      } finally {
        emit("change", {
          spaceId: select.value,
          inputValue: "",
        });
      }
    }
  });
  input.click();
  input.remove();
}
let promises = [];
//拖拽上传
const handleMultipleFileDrop = async (event) => {
  try {
    event.preventDefault();
    const items = event.dataTransfer.items;
    for (const item of items) {
      // 提取Entry对象
      const entry = item.webkitGetAsEntry();

      if (entry.isFile) {
        // 处理文件，拿到File文件
        const fileResult = await new Promise((resolve, reject) => {
          entry.file((file) => {
            resolve(file);
          });
        });
        await upLoad(fileResult);
      } else {
        // 处理文件夹，拿到FileEntry对象
        const reader = entry.createReader();
        const entriesResult = await new Promise((resolve, reject) => {
          reader.readEntries((entries) => {
            resolve(entries);
          });
        });
        await reHandleFile(entriesResult);
        await Promise.allSettled(promises);
        promises = [];
        console.log("无知");
      }
    }
  } finally {
    emit("change", {
      spaceId: select.value,
      inputValue: "",
    });
  }
};

// 如果文件夹是多级，则递归读取
const reHandleFile = async (entries) => {
  for (const entry of entries) {
    if (entry.isFile) {
      // 同步处理文件
      const fileResult = await new Promise((resolve, reject) => {
        entry.file((file) => {
          resolve(file);
        });
      });
      promises.push(upLoad(fileResult));
    } else {
      // 处理文件夹，拿到FileEntry对象
      const reader = entry.createReader();
      const entriesResult = await new Promise((resolve, reject) => {
        reader.readEntries((entries) => {
          resolve(entries);
        });
      });
      await reHandleFile(entriesResult);
    }
  }
};
const upLoad = (file) => {
  const fileId = Date.now() + Math.random(); // 生成唯一的文件ID
  uploadQueue.value.push({
    id: fileId,
    name: file.name,
    progress: 0,
    status: "uploading",
  });

  return new Promise(async (resolve, reject) => {
    try {
      const formData = new FormData();
      formData.append("file", file);
      formData.append("fileType", Number(proxy.$gf.gft(file.name).value));
      formData.append("remark", "真棒");
      formData.append("spaceId", select.value);

      const fileUrl = await addfile(formData, {
        spaceId: select.value,
      }, (val) => {
        // 更新文件的上传进度
        uploadProgress.value[fileId] = val;
        const index = uploadQueue.value.findIndex((item) => item.id === fileId);
        if (index !== -1) {
          uploadQueue.value[index].progress = val;
        }
        console.log(`文件---[${file.name}]---上传进度${val}`);
      });
      // console.log(fileUrl,fileUrl.fileUrl);
      // 文件上传完成，更新状态
      const index = uploadQueue.value.findIndex((item) => item.id === fileId);
      if (index !== -1) {
        uploadQueue.value[index].status = "success";
      }
      resolve("上传成功");
    } catch (error) {
      console.log(error);
      // 文件上传失败，更新状态
      const index = uploadQueue.value.findIndex((item) => item.id === fileId);
      if (index !== -1) {
        uploadQueue.value[index].status = "error";
      }
      reject("上传失败");
    }
  });
};
//点击上传文件
const handleFileUpload = () => {
  let input = document.createElement("input");
  input.type = "file";
  // 可以设置多个文件上传
  // input.multiple = true;
  // 可以设置文件类型过滤
  // input.accept = ".jpg,.png,.webp";
  input.addEventListener("change", async (event) => {
    // 获取选中的文件列表
    var files = event.target.files;
    for (var i = 0; i < files.length; i++) {
      var file = files[i];
      try {
        await upLoad(file);
      } catch (error) {
        console.log(error);
      } finally {
        emit("change", {
          spaceId: select.value,
          inputValue: "",
        });
      }
    }
  });
  input.click();
  input.remove();
};
//点击上传文件夹
const handleUploadDir = () => {
  let input = document.createElement("input");
  input.type = "file";
  input.webkitdirectory = true;
  input.mozdirectory = true;
  input.msdirectory = true;
  input.odirectory = true;
  input.directory = true;
  input.multiple = true;
  input.addEventListener("change", async (event) => {
    var files = event.target.files; // 获取文件夹中的所有文件（如果存在webkitdirectory属性）
    console.log(files);
    const uploadPromises = [];
    for (var i = 0; i < files.length; i++) {
      var file = files[i];
      uploadPromises.push(upLoad(file));
    }
    const results = await Promise.allSettled(uploadPromises);
    // 打印每个上传操作的结果
    results.forEach((result, index) => {
      if (result.status === "fulfilled") {
        console.log(`文件 ${index + 1} 上传成功:`, result.value);
      } else {
        console.log(`文件 ${index + 1} 上传失败:`, result.reason);
      }
    });
    emit("change", {
      spaceId: select.value,
      inputValue: "",
    });
  });
  input.click();
  input.remove();
};
//新建项目存储空间
const handleCreatItemDir = () => {
  ElMessageBox.prompt("请填写新项目文件存储目录名称", "尊敬的管理员，您好😊", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    inputPattern: /^[\p{L}\p{N}_]+$/u,
    inputErrorMessage: "无效名称命名,提示规则【a-zA-Z0-9中文(不含符号)】",
  })
    .then(async ({ value }) => {
      try {
        await addfilespace({
          spaceName: value,
        });
        await getFileSpaceList();
        ElMessage({
          type: "success",
          message: `创建成功:${value}空间`,
        });
      } catch (error) {
        ElMessage({
          message: error,
          type: "error",
          plain: true,
        });
      }
    })
    .catch(() => {
      ElMessage({
        type: "info",
        message: "取消创建",
      });
    });
};
const removeFileFromQueue = (fileId) => {
  uploadQueue.value = uploadQueue.value.filter((item) => item.id !== fileId);
};
</script>

<style lang="scss" scoped>
.logComponent {
  border-radius: 10px;
  padding: 10px;
  width: 400px;
  height: 400px;
  overflow: hidden;
  overflow-y: auto;
  background: black;
  color: #fff;
  @include scroll-bar(6px, #ccc);

  .row {}
}

// .uploadQuen {
//   width: 400px;
//   height: 400px;
//   overflow: hidden;
//   overflow-y: auto;
//   background: black;
//   color: #fff;
//   .uploadSuccess {
//     // background: yellow;
//   }
//   .uploadError {
//     // background: green;
//   }
// }
@keyframes example {
  from {
    background-color: red;
  }

  to {
    background-color: yellow;
  }
}

.animated-box {
  animation: example 4s ease 4s 2 normal forwards;
}

.test {
  height: 50px;
  position: relative;

  .block {
    position: absolute;
    width: 140px;
    top: 0px;
    height: 50px;
    display: flex;
    justify-content: center;
    align-items: center;
    margin: 0px;
    animation: upanddown 1s ease-in var(--index) normal forwards;
  }

  @keyframes upanddown {
    0% {
      transform: translateY(0) translateX(0px);
    }

    10%,
    30%,
    50%,
    70%,
    90% {
      transform: translateX(-2px);
    }

    20%,
    40%,
    60%,
    80% {
      transform: translateX(2px);
    }

    100% {
      top: 0px;
      transform: translateY(0) translateX(0px);
    }
  }
}

.nav {
  padding: 20px;
  box-sizing: border-box;
  width: 100%;
  position: sticky;
  top: 0px;
  left: 0px;
  z-index: 999;
  background-color: #fff;

  .nav-second {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;

    .input-box {
      width: 50%;
    }
  }

  #fileDragArea {
    height: 60px;
    background: #f5f4f4;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #ccc;
    width: 100%;
    border-radius: 10px;
    overflow: hidden;
    box-sizing: border-box;
    transition: all 0.5s ease;
  }
}
</style>

<style lang="scss" scoped>
.uploadQueue {
  margin-top: 20px;
  width: 600px;
  height: 200px;
  overflow: hidden;
  overflow-y: auto;
  background: rgb(21, 21, 21);
  color: #fff;
  padding: 10px;
  border-radius: 10px;
}

.upload-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.status-uploading {
  color: yellow;
}

.status-success {
  color: green;
}

.status-error {
  color: red;
}
</style>
